<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>3.分形图案</title>
    <style>
        canvas{
            border:1px solid #aaa;
            margin: 0 auto;
            display: block;
        }
    </style>
</head>
<body>
    <canvas width="400" height="400"></canvas>

    <script src="/common/lib/gl-renderer.js"></script>

    <script type="module">
        /**
         * gl-renderer 在 WebGL 底层的基础上进行了一些简单的封装，以便于我们将重点放在提供几何数据、设置变量和编写 Shader 上，不用因为创建 buffer 等细节而分心
         * 第一步: 创建 Renderer 对象
         * 第二步: 创建并启用 WebGL 程序
         * 第三步: 设置 uniform 变量
         * 第四步: 将顶点数据送入缓冲区
         * 第五步: 渲染
        */

        // 第一步:
        var canvas = document.querySelector("canvas")
        var renderer = new GlRenderer(canvas)

        var vertex = `
            //定义定点变量
            attribute vec2 a_vertexPosition;
            attribute vec2 uv;
            varying vec2 vUv;

            void main() {
                gl_PointSize = 1.0;
                vUv = uv;
                gl_Position = vec4(a_vertexPosition,1.0,1.0);
            }
        `

        // 分形公式（曼德勃罗特集）：Zn+1=Zn^2+C
        var fragment = `
            #ifdef GL_ES
                precision highp float;
            #endif
            varying vec2 vUv;
            uniform vec2 center;
            uniform float scale;
            uniform int iterations;

            // 分形公式（矩阵乘法表示两个复数相乘）
            vec2 f(vec2 z, vec2 c){
                return mat2(z, -z.y, z.x) * z + c;
            }

            void main(){
                vec2 uv = vUv;
                // 设置实数c的值
                vec2 c = center+ 4.0 * (uv - vec2(0.5)) / scale;
                vec2 z = vec2(0.0);

                bool escaped = false;
                int j;
                for(int i = 0; i < 65536; i++){
                    //达到循环次数就结束
                    if(i > iterations) break;
                    j = i;
                    //递归分形公式
                    z = f(z, c);
                    //如果模长大于2就不再执行
                    if(length(z) > 2.0){
                        escaped = true;
                        break;
                    }
                }
                gl_FragColor.rgb = escaped ? vec3(float(j)) / float(iterations) : vec3(0.0);
                gl_FragColor.a = 1.0;
            }
        `
        // 第二步：
        var program = renderer.compileSync(fragment,vertex)
        renderer.useProgram(program)
        
        // 第三步：
        renderer.uniforms.center = [0.0,0.0];
        renderer.uniforms.scale = 1.0;
        renderer.uniforms.iterations = 256;

        // 第四步：
        renderer.setMeshData([
            {
                // 顶点坐标
                positions:[
                    [-1,-1],
                    [-1,1],
                    [1,1],
                    [1,-1]
                ],
                // 设置变量
                attributes:{
                    // 纹理坐标
                    uv:[
                        [0,0],
                        [0,1],
                        [1,1],
                        [1,0]
                    ]
                },
                // 对顶点坐标进行三角剖分
                cells:[[0,1,2],[2,0,3]]
            }
        ])

        // 第五步：
        renderer.render()
    </script>
</body>
</html>